/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "imageknife_data_napi.h"
#include "napi_utils.h"
namespace ImageKnifePro {

// 将 imageData 所有属性逐个添加到 JS 对象
napi_value ImageKnifeDataNapi::ConvertToJSObject(napi_env env, const ImageInfo &data, bool failed)
{
    napi_value result;
    napi_create_object(env, &result); // 创建一个新的 JavaScript 对象
    SetBasicProperties(env, result, data);
    SetTimeInfoProperties(env, result, data.timeInfo);
    if (failed) {
        SetErrorInfoProperties(env, result, data.errorInfo);
    }

    return result;
}

// 设置基本属性
void ImageKnifeDataNapi::SetBasicProperties(napi_env env, napi_value result, const ImageInfo &data)
{
    NapiUtils::SetPropertyString(env, result, "requestId", data.requestId);
    NapiUtils::SetPropertyBoolean(env, result, "isMergedRequest", data.isMergedRequest);
    NapiUtils::SetPropertyInt32(env, result, "imageSourceFrom", static_cast<int32_t>(data.imageSourceFrom));
    NapiUtils::SetPropertyUint32(env, result, "imageWidth", data.imageWidth);
    NapiUtils::SetPropertyUint32(env, result, "imageHeight", data.imageHeight);
    NapiUtils::SetPropertyInt32(env, result, "type", static_cast<int32_t>(data.type));

    if (!data.customFormat.empty()) {
        NapiUtils::SetPropertyString(env, result, "customFormat", data.customFormat);
    }

    if (data.componentWidth != 0) {
        NapiUtils::SetPropertyUint32(env, result, "componentWidth", data.componentWidth);
    }
    if (data.componentHeight != 0) {
        NapiUtils::SetPropertyUint32(env, result, "componentHeight", data.componentHeight);
    }
    if (data.bufSize != 0) {
        NapiUtils::SetPropertyUint32(env, result, "bufSize", data.bufSize);
    }
    if (data.httpCode != 0) {
        NapiUtils::SetPropertyUint32(env, result, "httpCode", data.httpCode);
    }
    if (data.frameCount > 0) {
        NapiUtils::SetPropertyUint32(env, result, "frameCount", data.frameCount);
    }

    if (data.decodeImages.size() > 0) {
        // 创建 decodeImages 数组
        napi_value decodeImages;
        napi_create_array(env, &decodeImages);
        for (int i = 0; i < data.decodeImages.size(); ++i) {
            // 调用独立的 CreateImageInfo 函数创建 JavaScript 对象并添加到数组中
            napi_value jsImageInfo = CreateImageInfo(env, data.decodeImages[i].contentWidth,
                                                     data.decodeImages[i].contentHeight);
            napi_set_element(env, decodeImages, i, jsImageInfo);
        }
        napi_set_named_property(env, result, "decodeImages", decodeImages);
    }

    if (data.transformationInfos.size() > 0) {
        napi_value transformationInfos;
        napi_create_array(env, &transformationInfos);
        for (int i = 0; i < data.transformationInfos.size(); ++i) {
            napi_value value = CreateTransformationInfo(env, data.transformationInfos[i]);
            napi_set_element(env, transformationInfos, i, value);
        }
        napi_set_named_property(env, result, "transformationInfos", transformationInfos);
    }
}

napi_value ImageKnifeDataNapi::CreateTransformationInfo(napi_env env, const TransformationInfo &info)
{
    napi_value result;
    napi_create_object(env, &result);

    NapiUtils::SetPropertyString(env, result, "desc", info.desc);
    NapiUtils::SetPropertyTimeStamp(env, result, "startTime", info.startTime);
    NapiUtils::SetPropertyTimeStamp(env, result, "endTime", info.endTime);
    NapiUtils::SetPropertyBoolean(env, result, "isSuccess", info.isSuccess);
    return result;
}

napi_value ImageKnifeDataNapi::CreateImageInfo(napi_env env, const uint32_t &width, const uint32_t &height)
{
    napi_value obj;
    napi_status status = napi_create_object(env, &obj); // 创建对象
    if (status != napi_ok) {
        return nullptr;
    }

    NapiUtils::SetPropertyUint32(env, obj, "contentWidth", width);
    NapiUtils::SetPropertyUint32(env, obj, "contentHeight", height);
    return obj;
}

// 设置 TimeInfo 属性
void ImageKnifeDataNapi::SetTimeInfoProperties(napi_env env, napi_value result, const TimeInfo& timeInfo)
{
    napi_value timeInfoObj;
    napi_create_object(env, &timeInfoObj);

    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "executeTime", timeInfo.executeTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "requestStartTime", timeInfo.requestStartTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "requestEndTime", timeInfo.requestEndTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "requestCancelTime", timeInfo.requestCancelTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "memoryCheckStartTime", timeInfo.memoryCheckStartTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "memoryCheckEndTime", timeInfo.memoryCheckEndTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "diskCheckStartTime", timeInfo.diskCheckStartTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "diskCheckEndTime", timeInfo.diskCheckEndTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "loadImageStartTime", timeInfo.loadImageStartTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "loadImageEndTime", timeInfo.loadImageEndTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "decodeStartTime", timeInfo.decodeStartTime);
    NapiUtils::SetPropertyTimeStamp(env, timeInfoObj, "decodeEndTime", timeInfo.decodeEndTime);

    napi_set_named_property(env, result, "timeInfo", timeInfoObj);
}

// 设置 ErrorInfo 属性
void ImageKnifeDataNapi::SetErrorInfoProperties(napi_env env, napi_value result, const ErrorInfo& errorInfo)
{
    napi_value errorInfoObj;
    napi_create_object(env, &errorInfoObj);

    NapiUtils::SetPropertyString(env, errorInfoObj, "phase", errorInfo.phase);
    NapiUtils::SetPropertyInt32(env, errorInfoObj, "code", static_cast<int32_t>(errorInfo.code));

    napi_set_named_property(env, result, "errorInfo", errorInfoObj);
}

uint64_t ImageKnifeDataNapi::GetTimestamp()
{
    auto now = std::chrono::system_clock::now();
    auto epoch = now.time_since_epoch();
    auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
    return static_cast<uint64_t>(milliseconds.count());
}

std::unordered_map<LoadPhase, std::string> ImageKnifeDataNapi::phaseToStringMap = {
    {LoadPhase::DISPATCH, "dispatch"},
    {LoadPhase::MEMORY_CACHE, "memoryCache"},
    {LoadPhase::FILE_CACHE, "fileCache"},
    {LoadPhase::LOAD_IMAGE_FETCH, "loadImageFetch"},
    {LoadPhase::DECODE, "decode"},
    {LoadPhase::DOWN_SAMPLE, "downSample"},
    {LoadPhase::TRANSFORM, "transform"}
};
} // namespace ImageKnifePro
